package org.tech4j.springboot.starter.edi.common.handler;

import com.google.common.collect.Lists;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.tech4j.edi.api.factory.RetryHandleFactory;
import org.tech4j.edi.common.RetryHandle;
import org.tech4j.springboot.starter.ext.utils.SpringUtils;

import java.util.List;
import java.util.Map;

/**
 * @program: tech4j
 * @description: 从ApplicationContext中获取RetryHandle
 *               这里主要是处理RetryHandler存在事务问题，可以使用该方式，但是前提是必须要加载到Spring容器
 * @author: YuKai Fan
 * @create: 2025/3/7 22:10
 **/
public class ApplicationContextRetryHandleFactory implements RetryHandleFactory {
    @Override
    public void registerHandle(String bizType, RetryHandle retryHandle) {
        ApplicationContext applicationContext = SpringUtils.getInstance().getApplicationContext();
        if (applicationContext instanceof ConfigurableApplicationContext configurableApplicationContext) {
            DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(retryHandle.getClass());
            rootBeanDefinition.setScope(RootBeanDefinition.SCOPE_SINGLETON);

            // 注册bean
            beanFactory.registerBeanDefinition(bizType, rootBeanDefinition);

            // 注册bean实例
            beanFactory.registerSingleton(bizType, retryHandle);
        } else {
            throw new IllegalStateException("ApplicationContext is not an instance of ConfigurableApplicationContext");
        }
    }

    @Override
    public RetryHandle getRetryHandle(String bizType) {
        return SpringUtils.getInstance().getBean(bizType);
    }

    @Override
    public RetryHandle getRetryHandle(Class<? extends RetryHandle> handleClass) {
        return SpringUtils.getInstance().getBean(handleClass);
    }

    @Override
    public List<String> getRetryType() {
        ApplicationContext applicationContext = SpringUtils.getInstance().getApplicationContext();
        Map<String, RetryHandle> beansOfType = applicationContext.getBeansOfType(RetryHandle.class);
        return Lists.newArrayList(beansOfType.keySet());
    }
}
